package com.vast.ui.lcdpanel.models;

import org.eclipse.swt.SWTException;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;

public class SwtImageLayer {
	private static final PaletteData PALETTE_RGB = new PaletteData(0xFF0000, 0xFF00, 0xFF);
	private static final PaletteData PALETTE_GBR = new PaletteData(0xFF0000, 0xFF00, 0xFF);
	public  int           x;
	public  int           y;
	private int           layerNo;
	private boolean       isVisible;
	private Image         swtImage;
	private ImageData     swtImageData;
	private final Display display;
	private boolean       imageDataChanged;
	
	/**
	 * Constructs a new instance of this class given its parent.
	 * @param parent a composite control which will be the parent of the new instance (cannot be null)
	 */
	public  SwtImageLayer(Composite parent) {
		this.display = parent.getDisplay();
		this.x = 0;
		this.y = 0;
		this.layerNo   = 0;
		this.isVisible = false;
		this.imageDataChanged = false;
	}
	
	/**
	 * Constructs a new, empty ImageData with the given width, height,
	 * depth, palette, scanlinePad and data.
	 *
	 * @param width the width of the image
	 * @param height the height of the image
	 * @param depth the depth of the image
	 * @param palette the palette of the image
	 * @param alpha the padding of each line, in bytes
	 * @param data the data of the image
	 *
	 */
	public void createDirectColorImageData(int width, int height, int depth, int alpha, byte[] rawData) {
		int scanlinePad = 4;
		this.swtImageData = new ImageData(width, height, depth, this.PALETTE_RGB, scanlinePad, rawData);
		this.swtImageData.alpha = alpha;
		this.imageDataChanged = true;
	}
	
	public void setImageData(ImageData imageData) {
		this.swtImageData = imageData;
		this.imageDataChanged = true;
	}
	
	public void updateImage() {
		if(!this.imageDataChanged) return;
		
		if(this.swtImage != null)
			this.swtImage.dispose();
		this.swtImage = new Image(this.display, this.swtImageData);
		
		this.imageDataChanged = false;
	}
	
	/**
	 * Set the global alpha value to be used for every pixel.
	 * <p>
	 * If this value is set, the <code>alphaData</code> field
	 * is ignored and when the image is rendered each pixel
	 * will be blended with the background an amount
	 * proportional to this value.
	 * </p><p>
	 * The default is -1 which means 'no global alpha value'
	 * </p>
	 * @param alpha the alpha to be used for every pixel
	 */
	public void setGlobalAlpha(int alpha) {
		if (this.swtImageData == null) return;
		
		this.swtImageData.alpha = alpha;
		this.imageDataChanged   = true;
	}
	
	/**
	  * Dispose the resources attached to this layer.
	  */
	public void dispose() {
	   if (swtImage != null) swtImage.dispose();
	   
	   this.swtImageData = null;
	   this.imageDataChanged = false;
	}
	
	public Image getImage() {
		updateImage();
		return this.swtImage;
	}
	
	public void setVisible(boolean isVisible) {
		this.isVisible = isVisible;
		this.imageDataChanged = isVisible;
	}
	
	public boolean isVisible() {
		return this.isVisible;
	}
	
	public void setLayerNo(int no) {
		this.layerNo = no;
	}
	
	public int getLayoutNo() {
		return this.layerNo;
	}
	
	public void setLocation(int x, int y) {
		this.x = x;
		this.y = y;
	}
	
	public int getX() {
		return this.x;
	}
	
	public int getY() {
		return this.y;
	}

	/**
	 * Sets the alpha value at offset <code>x</code> in
	 * scanline <code>y</code> in the receiver's alpha data.
	 *
	 * @param x the x coordinate of the alpha value to set
	 * @param y the y coordinate of the alpha value to set
	 * @param alpha the value to set the alpha to
	 *
	 * @exception IllegalArgumentException <ul>
	 *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
	 *  </ul>
	 */
	public void setAlpha(int x, int y, int alpha) {
		this.swtImageData.setAlpha(x, y, alpha);
		this.imageDataChanged = true;
	}
	
	/**
	 * Sets the alpha values starting at offset <code>x</code> in
	 * scanline <code>y</code> in the receiver's alpha data to the
	 * values from the array <code>alphas</code> starting at
	 * <code>startIndex</code>.
	 *
	 * @param x the x coordinate of the pixel to being setting the alpha values
	 * @param y the y coordinate of the pixel to being setting the alpha values
	 * @param putWidth the width of the alpha values to set
	 * @param alphas the alpha values to set
	 * @param startIndex the index at which to begin setting
	 *
	 * @exception IndexOutOfBoundsException if putWidth is too large
	 * @exception IllegalArgumentException <ul>
	 *    <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
	 *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
	 *    <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li>
	 * </ul>
	 */
	public void setAlphas(int x, int y, int putWidth, byte[] alphas, int startIndex) {
		this.swtImageData.setAlphas(x, y, putWidth, alphas, startIndex);
		this.imageDataChanged = true;
	}
	
	/**
	 * Sets the pixel value at offset <code>x</code> in
	 * scanline <code>y</code> in the receiver's data.
	 *
	 * @param x the x coordinate of the pixel to set
	 * @param y the y coordinate of the pixel to set
	 * @param pixelValue the value to set the pixel to
	 *
	 * @exception IllegalArgumentException <ul>
	 *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
	 * </ul>
	 * @exception SWTException <ul>
	 *    <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
	 * </ul>
	 */
	public void setPixel(int x, int y, int pixelValue) {
		this.swtImageData.setPixel(x, y, pixelValue);
		this.imageDataChanged = true;
	}
	
	/**
	 * Sets the pixel values starting at offset <code>x</code> in
	 * scanline <code>y</code> in the receiver's data to the
	 * values from the array <code>pixels</code> starting at
	 * <code>startIndex</code>.
	 *
	 * @param x the x position of the pixel to set
	 * @param y the y position of the pixel to set
	 * @param putWidth the width of the pixels to set
	 * @param pixels the pixels to set
	 * @param startIndex the index at which to begin setting
	 *
	 * @exception IndexOutOfBoundsException if putWidth is too large
	 * @exception IllegalArgumentException <ul>
	 *    <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
	 *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
	 *    <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li>
	 * </ul>
	 * @exception SWTException <ul>
	 *    <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8
	 *        (For higher depths, use the int[] version of this method.)</li>
	 * </ul>
	 */
	public void setPixels(int x, int y, int putWidth, byte[] pixels, int startIndex) {
		this.swtImageData.setPixels(x, y, putWidth, pixels, startIndex);
		this.imageDataChanged = true;
	}
	
	/**
	 * Sets the pixel values starting at offset <code>x</code> in
	 * scanline <code>y</code> in the receiver's data to the
	 * values from the array <code>pixels</code> starting at
	 * <code>startIndex</code>.
	 *
	 * @param x the x position of the pixel to set
	 * @param y the y position of the pixel to set
	 * @param putWidth the width of the pixels to set
	 * @param pixels the pixels to set
	 * @param startIndex the index at which to begin setting
	 *
	 * @exception IndexOutOfBoundsException if putWidth is too large
	 * @exception IllegalArgumentException <ul>
	 *    <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
	 *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
	 *    <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li>
	 * </ul>
	 * @exception SWTException <ul>
	 *    <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
	 * </ul>
	 */
	public void setPixels(int x, int y, int putWidth, int[] pixels, int startIndex) {
		this.swtImageData.setPixels(x, y, putWidth, pixels, startIndex);
		this.imageDataChanged = true;
	}

}
